﻿using AutoMapper;
using DFGK_WMS.Context;
using DFGK_WMS.IRepository;
using DFGK_WMS.Model.Enum;
using DFGK_WMS.Model.Models;
using Microsoft.EntityFrameworkCore;
using NPOI.SS.Formula.Functions;
using System.Linq.Expressions;

namespace DFGK_WMS.Repository
{
    public class TShippingLockCellRepository : BaseRepository<TShippingLockCell>, ITShippingLockCellRepository
    {
        public TShippingLockCellRepository(DFGK_DB Context, IMapper mapper) : base(Context, mapper)
        {
        }

        public bool LockCell(int materialId, decimal expectedQTY, out List<TShippingLockCell> lockCellList, out string errorMsg, int? ownerId=null, string? BatchNo=null, int? supplierId = null)
        {
            errorMsg = "";
            lockCellList = new List<TShippingLockCell>();
            try
            {
                //查询出库的物料
                var materialList = Context.TMaterial.Where(t => t.Id == materialId);
                if (materialList == null)
                {
                    errorMsg = "物料数据不存在";
                    return false;
                }
                var material= materialList.FirstOrDefault();

                var cellQuery = Context.TCells;
                var shelfQuery = Context.TShelves;
                var TInventoryQuery = (from inv in Context.TInventories
                                      join cell in cellQuery
                                      on inv.LocationId equals cell.Id
                                      join slf in shelfQuery
                                      on cell.ShelfId equals slf.Id                                   
                                      where cell.Status==1 && slf.Status==1
                                      select inv
                                      ).ToList();
   
                var invList = TInventoryQuery.Where(t => t.MaterialId == materialId && t.Status == 1 && t.IsLock == false).ToList();
                //if (!string.IsNullOrEmpty(BatchNo))
                //{
                //    invList = invList.Where(t => t.BatchNo == BatchNo).ToList();
                //}
             
                if (supplierId > 0)
                {
                    invList = invList.Where(t => t.SupplierId == supplierId).ToList();
                }
                decimal? sum = invList.Sum(t => t.AvailableQty);
                List<int?> status = new List<int?>
                {
                    (int)EmBillStatus.Create,
                    (int)EmBillStatus.Submit,
                    (int)EmBillStatus.Pass,
                };
                //一键出库优先级最高
                var shippingOrderDetailQuery = Context.TShippingOrderDetails.OrderBy(t => t.CreateDate);
                var slcOdQuery = (from lockCell in Context.TShippingLockCells
                                  join od in shippingOrderDetailQuery
                                  on lockCell.OrderDetailId equals od.Id
                                  select new { lockCell,od }
                                ).ToList();
                var slcOdQueryTest = slcOdQuery.ToList();
                List<TShippingLockCell> lockCells = slcOdQuery.Select(x => x.lockCell).ToList();
                List<TShippingOrderDetail> orderDetails = slcOdQuery.Select(x => x.od).ToList();

                
                orderDetails = orderDetails.Where(od => /*od.MaterialId == materialId &&*/ status.Contains(od.Status)).ToList();
                lockCells = lockCells.Where(loc => loc.MaterialId == materialId).ToList();
                slcOdQuery = (from lockCell in lockCells
                                join od in orderDetails
                                on lockCell.OrderDetailId equals od.Id
                                select new { lockCell, od }
                        ).ToList();


                //剔除被锁定的库存
                var lockInvIdQuery = (from lockCell in lockCells
                                      join od in orderDetails
                                      on lockCell.OrderDetailId equals od.Id
                                      where lockCell.IsPicking == true
                                      select lockCell.InventoryId
                            ).Distinct().ToList();
                int lockInvCount = lockInvIdQuery.Count();
                if (lockInvCount > 0)
                {
                    invList = invList.Where(t => !lockInvIdQuery.ToList().Contains(t.Id)).ToList();
                }
                //查出所有匹配的库存  出库优先级规则
                List<TInventory> TInventoryList = invList.OrderBy(x => x.LocationDepth)
                                                        .ThenBy(x => x.InStockShortDate)
                                                        .ThenByDescending(x => x.AvailableQty)
                                                        .ThenBy(x => x.LocationLineNo)
                                                        .ThenBy(x => x.LocationLayerNo)
                                                        .ThenBy(x => x.LocationColumnNo)
                                                        //.ThenBy(x => ExtractDateFromCode(x.BatchNo))
                                                        .ToList();
                //库存可用数量
                decimal totalTInventoryCount = TInventoryList.Sum(t => t.AvailableQty.GetValueOrDefault());

                List<TInventory> allotTInventoryList = new List<TInventory>();
                List<TInventory> unAllotTInventoryList = new List<TInventory>();
                TInventory lastAllotTInventory = null;
                decimal qty = 0;
                if (expectedQTY > totalTInventoryCount)
                {
                    errorMsg = "库存数量不足" + expectedQTY.ToString()+"。目前可出数量："+ (int)totalTInventoryCount;
                    if (sum.GetValueOrDefault() >= expectedQTY)
                    {
                        errorMsg += "，部分库存可能已被其它出库单锁定";
                    }
                    return false;
                }
                //TInventoryList = TInventoryList.OrderBy(t => t.LocationLineNo).ThenBy(t => t.LocationLayerNo).ThenBy(t => t.LocationColumnNo).ThenBy(t => t.LocationDepth)
                //    .ThenBy(t => t.InStockDate).ThenByDescending(t => t.AvailableQty).ThenBy(t => t.LocationDepth).ToList();

                var groupInvs = TInventoryList.GroupBy(t => new { t.LocationLineNo, t.LocationLayerNo, t.LocationColumnNo });
                foreach (var group in groupInvs)
                {
                    List<TInventory> list = group.OrderBy(t => t.LocationDepth).ToList();
                    FilterInv(list, expectedQTY, ref qty, ref allotTInventoryList, ref unAllotTInventoryList);
                    if (qty >= expectedQTY)
                    {
                        break;
                    }
                }

                if (qty < expectedQTY && unAllotTInventoryList.Count > 0)
                {
                    lastAllotTInventory = unAllotTInventoryList.Where(t => qty + t.AvailableQty.GetValueOrDefault() == expectedQTY).OrderBy(t => t.LocationDepth).ThenBy(t => t.InStockShortDate).FirstOrDefault();
                    if (lastAllotTInventory == null)
                    {
                        List<string> allotColumns = allotTInventoryList != null && allotTInventoryList.Count > 0 ? allotTInventoryList.Select(t => t.LocationLineNo.ToString() + "_" + t.LocationLayerNo.ToString() + "_" + t.LocationColumnNo.ToString()).Distinct().ToList() : new List<string>();
                        lastAllotTInventory = unAllotTInventoryList.Where(t => !allotColumns.Contains(t.LocationLineNo.ToString() + "_" + t.LocationLayerNo.ToString() + "_" + t.LocationColumnNo.ToString())).OrderBy(t => t.LocationDepth).ThenBy(t => t.InStockShortDate).FirstOrDefault();
                        if (lastAllotTInventory == null)
                        {
                            lastAllotTInventory = unAllotTInventoryList.OrderBy(t => t.LocationDepth).ThenBy(t => t.InStockShortDate).FirstOrDefault();
                        }
                    }
                    else
                    {
                        allotTInventoryList.Add(lastAllotTInventory);
                        qty += lastAllotTInventory.AvailableQty.GetValueOrDefault();
                    }
                }

                if (qty + (lastAllotTInventory == null ? 0 : lastAllotTInventory.AvailableQty.GetValueOrDefault()) < expectedQTY)
                {
                    errorMsg = "可锁定的库存数量不足" + expectedQTY.ToString() + "，可能存在浅位库存在做其它业务";
                    return false;
                }
                int index = 0;
                if (allotTInventoryList != null && allotTInventoryList.Count > 0)
                {
                    foreach (var TInventory in allotTInventoryList)
                    {
                        index++;
                        lockCellList.Add(new TShippingLockCell
                        {
                            CellId = TInventory.LocationId,
                            CellCode = TInventory.LocationCode,
                            CellName = TInventory.LocationName,
                            CellDepthIndex = TInventory.LocationDepth,
                            InventoryId = TInventory.Id,
                            InventoryQty = TInventory.AvailableQty,
                            LockIndex = index,
                            MaterialCode = TInventory.MaterialCode,
                            MaterialId = TInventory.MaterialId,
                            MaterialName = TInventory.MaterialName,
                            OutQty = TInventory.AvailableQty,
                            PalletBarcode = TInventory.PalletBarcode,
                            IsPicking = false,
                            StackingStorageId = TInventory.StackingStorageId,
                            WhId = TInventory.WarehouseId,
                            CreateDate = TInventory.CreateDate,
                            DateTime = DateTime.Now
                        });
                    }
                }

                if (lastAllotTInventory != null)
                {
                    decimal lastQty = expectedQTY - qty;
                    if (lastQty > 0)
                    {
                        index++;
                        lockCellList.Add(new TShippingLockCell
                        {
                            CellId = lastAllotTInventory.LocationId,
                            CellCode = lastAllotTInventory.LocationCode,
                            CellName = lastAllotTInventory.LocationName,
                            CellDepthIndex = lastAllotTInventory.LocationDepth,
                            InventoryId = lastAllotTInventory.Id,
                            InventoryQty = lastAllotTInventory.AvailableQty,
                            LockIndex = index,
                            MaterialCode = lastAllotTInventory.MaterialCode,
                            MaterialId = lastAllotTInventory.MaterialId,
                            MaterialName = lastAllotTInventory.MaterialName,
                            OutQty = lastQty,
                            PalletBarcode = lastAllotTInventory.PalletBarcode,
                            IsPicking = lastQty < lastAllotTInventory.AvailableQty.GetValueOrDefault(),
                            StackingStorageId = lastAllotTInventory.StackingStorageId,
                            WhId = lastAllotTInventory.WarehouseId,
                            CreateDate = lastAllotTInventory.CreateDate,
                            DateTime = DateTime.Now
                        });
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                errorMsg = "未知异常:" + ex.Message;
                return false;
            }
        }
        private void FilterInv(List<TInventory> list, decimal expectedQTY, ref decimal qty, ref List<TInventory> allotInventoryList, ref List<TInventory> unAllotInventoryList)
        {
            //先找有没有正好数量的库存
            //foreach (var inventory in list)
            //{
            //    if (inventory.AvailableQty == expectedQTY)
            //    {
            //        allotInventoryList.Add(inventory);
            //        qty += inventory.AvailableQty.GetValueOrDefault();
            //        break;
            //    }
            //}
            //if (allotInventoryList == null || allotInventoryList.Count() == 0)
            //{
                foreach (var inventory in list)
                {
                    if (qty == expectedQTY)
                    {
                        break;
                    }
                    if (qty + inventory.AvailableQty.GetValueOrDefault() == expectedQTY)
                    {
                        allotInventoryList.Add(inventory);
                        qty += inventory.AvailableQty.GetValueOrDefault();
                        break;
                    }
                    //数量多的
                    else if (qty + inventory.AvailableQty.GetValueOrDefault() > expectedQTY)
                    {
                        unAllotInventoryList.Add(inventory);
                        break;
                    }
                    else
                    {
                        allotInventoryList.Add(inventory);
                        qty += inventory.AvailableQty.GetValueOrDefault();
                    }
                }
            //}
        }
        /// <summary>
        /// 批次号拆解
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        public DateTime ExtractDateFromCode(string bacNo)
        {
            string code = bacNo.Split('-')[1];
            var monthMapping = new Dictionary<string, int>
            {
                {"A", 1},
                {"B", 2},
                {"C", 3},
                {"D", 4},
                {"E", 5},
                {"F", 6},
                {"G", 7},
                {"H", 8},
                {"I", 9},
                {"J", 10},
                {"K", 11},
                {"L", 12}
            };

            string yearPart = "20" + code.Substring(2, 2);
            string monthPart = code.Substring(4, 1);
            string dayPart = code.Substring(5, 2);
            int year = int.Parse(yearPart);
            int day = int.Parse(dayPart);
            int month = monthMapping[monthPart.ToUpper()];
            return new DateTime(year, month, day);
        }

    }

}
